home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / overview / moreisbetter / mib-libraries / moremenus / moresystemmenus.h < prev   
Encoding:
C/C++ Source or Header  |  2000-09-28  |  13.8 KB  |  330 lines

  1. /*
  2.     File:        MoreSystemMenus.h
  3.  
  4.     Contains:    Module for adding iconic menus to the right of the menu bar.
  5.  
  6.     Written by:    Quinn, Pete Gontier
  7.  
  8.     Copyright:    Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20.          <1>     25/8/99    Quinn   First checked in.
  21. */
  22.  
  23. #pragma once
  24.  
  25. /////////////////////////////////////////////////////////////////
  26.  
  27. // MIB Setup
  28.  
  29. #include "MoreSetup.h"
  30.  
  31. // Mac OS Interfaces
  32.  
  33. #include <MacTypes.h>
  34. #include <Menus.h>
  35. #include <Icons.h>
  36.  
  37. /////////////////////////////////////////////////////////////////
  38.  
  39. #ifdef __cplusplus
  40.     extern "C" {
  41. #endif
  42.  
  43. #pragma import off    // for clients
  44. #pragma export off  // for building a library
  45.  
  46. /////////////////////////////////////////////////////////////////
  47.  
  48. // The architecture used by MoreSystemMenus relies on the fact
  49. // that system menus can be created by a system extension (INIT).
  50. // As Carbon does not support the building of system extensions,
  51. // this module can not be used by Carbon code.
  52.  
  53. #if TARGET_API_MAC_CARBON
  54.     #error MoreSystemMenus is not Carbon compatible.
  55. #endif
  56.  
  57. /////////////////////////////////////////////////////////////////
  58.  
  59. /*    Overall Comments
  60.     ----------------
  61.     
  62.     o System menus are *bad* human interface design!  Apple
  63.       recognises this fundamental truth, and tries to minimise
  64.       its use of system menus.  For example, earlier versions of
  65.       the system included a system menu to choose the current
  66.       printer; that function has moved to the control strip
  67.       in current system software.
  68.  
  69.     o System menus are *bad* engineering.  To implement a system
  70.       menu, you must patch traps and muck with undocumented low-memory
  71.       globals.  Doing this will introduce a compatibility liability
  72.       in your product.  Specifically, using a system menu will
  73.       guarantee that your product is *not* Carbon compatible.
  74.     
  75.     o Apple will not introduce an API for system menus in Carbon
  76.       (or any other system) because system menus are bad HI design.
  77.     
  78.     o This code exists because:
  79.     
  80.         o We (DTS) recognise that you (third party developers) are going
  81.           to implement system menus regardless of how much we tell you 
  82.           not to, often because your marketting organisation demands them.
  83.           Furthermore, users will install your products without knowing
  84.           that they are based on unsupport technology.  If you implement
  85.           system menus badly, you will compromise the stability of user
  86.           systems, which is not in Apple's interest.
  87.         
  88.         o It's in Apple's interest for all system menus to be implemented
  89.           in the same way.  This makes it easier for our engineering 
  90.           organisation to maintain compatibility between releases.
  91.           This is no guarantee of compatibility, of course, but it's
  92.           always safer in a big herd than a small herd.
  93.     
  94.     o The routines described below are *SAMPLE CODE*, not an
  95.       Apple-sanctioned programming interface.  Read the disclaimer at
  96.       the top of this file for more details of what this means.
  97.     
  98.     o All routines must be called at system task time.
  99.  
  100.     o Be wary of menu IDs shifting out from underneath you.
  101.       See the comments for InsertSystemMenu and InsertSystemSubMenu
  102.       for details.
  103.  
  104.     o Note on Recursion -- When writing system menu code, you have
  105.       to be very careful to avoid dying because of recursion.
  106.       The MoreSystemMenus calls your callback from a patch on
  107.       MenuSelect.  If your callback calls MenuSelect (either
  108.       directly, or indirectly, for example by calling ModalDialog
  109.       or something that calls ModalDialog), then MenuSelect
  110.       is being called recursively.
  111.       
  112.       There are two distinct cases.  MoreSystemMenus handles against
  113.       re-entrancy from your kSystemMenuActOnChosen callback.  For
  114.       example, if your kSystemMenuActOnChosen callback poses a modal
  115.       dialog, which in turn calls MenuSelect, all will be well.
  116.       
  117.       However, MoreSystemMenus doesn't handle recursion from your
  118.       kSystemMenuPreSelectAdjust and kSystemMenuPostSelectAdjust
  119.       callbacks.  If these callbacks call MenuSelect, MoreSystemMenus
  120.       will not crash, but it will also not handle any selections
  121.       on your menus.  You should avoid making calls to MenuSelect
  122.       from these callbacks.
  123.  
  124.       Also, your own code must guard against recursion, even in
  125.       the kSystemMenuActOnChosen.  For example, if you have a 
  126.       system menu whose callback poses a modal dialog, you should 
  127.       be aware that the callback might be called again from
  128.       within ModalDialog.  If you don't want this to happen,
  129.       you should set a global variable (before calling ModalDialog)
  130.       that causes your kSystemMenuPreSelectAdjust to disable the
  131.       menu item for menu operations while the modal dialog is up.
  132.  
  133.     o Command Keys -- MoreSystemMenus does not handle command keys
  134.       in system menus.  Extending it to do this would be relatively
  135.       easy (it would need to patch more traps, specifically MenuKey
  136.       and MenuEvent) but I didn't do this because the human interface
  137.       of putting command keys on system menus is even more questionable
  138.       than the HI of system menus themselves (-:
  139. */
  140.  
  141. /////////////////////////////////////////////////////////////////
  142.  
  143. // General utility routines
  144.  
  145. extern pascal MenuRef GetNewSystemMenu(SInt16 menuResourceID);
  146.     // This routine creates a new menu in the system heap based
  147.     // on the 'MENU' resource with the given ID.
  148.     //
  149.     // The menu is detached from the resource file, so you can
  150.     // safely close the resource file containing the 'MENU' resource.
  151.     // Also, this means you must DisposeMenu the menu if you don't
  152.     // insert it into the menu bar.
  153.     //
  154.     // Calling this routine twice will yield two distinct menus,
  155.     // so the semantics are somewhat different from the classic
  156.     // GetMenu (but close to the Carbon semantics).
  157.  
  158. extern pascal MenuRef NewSystemMenu(ConstStr255Param title);
  159.     // This routine creates a new, empty menu in the system heap.
  160.     // It's a close analogue to NewMenu.
  161.  
  162. extern pascal OSStatus GetDetachedIconSuite(IconSuiteRef *theIconSuite, SInt16 theResID, IconSelectorValue selector);
  163.     // This routine is a direct analogue of GetIconSuite except
  164.     // that the icons in the suite are detached from their parent
  165.     // resource file.
  166.  
  167. extern pascal void IconSuiteToSystemMenuTitle(IconSuiteRef theIconSuite, StringPtr menuTitle);
  168.     // This routine sets menuTitle such that the title will draw
  169.     // theIconSuite instead of text.  This only takes 6 bytes of
  170.     // storage, so we pass in a StringPtr rather than a Str255.
  171.  
  172. extern pascal OSStatus SetMenuTitleToIconSuite(MenuRef theMenu, IconSuiteRef theIconSuite);
  173.     // This routine sets the title of theMenu to the icon given
  174.     // in theIconSuite.  The current title of theMenu must be exactly 5
  175.     // characters long (otherwise you get a paramErr), although the
  176.     // contents of the current title are ignored.
  177.     //
  178.     // theIconSuite is *not* owned by theMenu after this call.
  179.     // If you dispose of the menu, you must subsequently dispose
  180.     // of theIconSuite.
  181.  
  182. // Startup
  183.  
  184. extern pascal OSStatus InitMoreSystemMenus(void);
  185.     // This routine initialises the MoreSystemMenus module.  It
  186.     // must be called at system startup time.  It must be called
  187.     // before any of the other routines in this module.  If it returns
  188.     // an error, you must not call any other routines in this module,
  189.     // although you are guaranteed that this module has no hooks into
  190.     // the system and you can unload the module's code.
  191.  
  192. // Core system menu routines
  193.  
  194. typedef pascal OSStatus (*SystemMenuCallbackProc)(OSType selector,
  195.                                                     MenuRef theMenu,
  196.                                                     void *param, 
  197.                                                     void *refcon);
  198.     // When adding a system menu, you must supply a pointer
  199.     // to a callback routine with the above prototype.
  200.     // When the system calls you back, selector is one of the messages
  201.     // (described) below and refcon is the refcon you supplied when
  202.     // you added the menu.  The other parameters are message-dependent.
  203.     //
  204.     // The callback is always made at system task time, although
  205.     // not in any particular application's context (it will probably
  206.     // be the context of the frontmost application).  68K code must
  207.     // set up its global world register (A4 for CodeWarrior code resources
  208.     // A5 for MPW code resources) before accessing any global variables.
  209.     //
  210.     // This is not a UPP because you get the source code to the
  211.     // MoreSystemMenus module; making it a UPP would complicate things
  212.     // without any real benefit.
  213.  
  214. enum {
  215.     kSystemMenuPreSelectAdjust  = 'prsl',
  216.         // MoreSystemMenus calls your SystemMenuCallbackProc routine
  217.         // with this selector to tell you to adjust the
  218.         // specified root system menu prior to the user
  219.         // being able to browse the menus (ie from a head patch
  220.         // on MenuSelect).  Typically this involves enabling
  221.         // or disabling items, but you can also add sub-menus
  222.         // using InsertSystemSubMenu.  If you add a sub-menu,
  223.         // you are also responsible for adjusting it before
  224.         // returning from this call.
  225.         //
  226.         // o theMenu is the MenuHandle of the root system menu
  227.         // o param is not defined
  228.         //
  229.         // Your implementation of this selector should not
  230.         // call MenuSelect (directly or indirectly).
  231.         // See "Notes on Recursion" (above) for more details.
  232.  
  233.     kSystemMenuPostSelectAdjust = 'posl',
  234.         // MoreSystemMenus calls your SystemMenuCallbackProc routine
  235.         // with this selector after the user has finished
  236.         // choosing a menu item (ie a tail patch
  237.         // on MenuSelect).  You can use this to 'de-adjust'
  238.         // your system menus (if necessary).
  239.         //
  240.         // o theMenu is the MenuHandle of the root system menu
  241.         // o param is not defined
  242.         //
  243.         // Your implementation of this selector should not
  244.         // call MenuSelect (directly or indirectly).
  245.         // See "Notes on Recursion" (above) for more details.
  246.  
  247.     kSystemMenuActOnChosen      = 'act!'
  248.         // MoreSystemMenus calls your SystemMenuCallbackProc routine
  249.         // with this selector when one of your menu items
  250.         // has been chosen by the user.  You must act on that
  251.         // item, by doing whatever your extension does.
  252.         //
  253.         // o theMenu is MenuHandle of the chosen menu.
  254.         //   This may be the root system menu or one
  255.         //   of your hierarchical sub-menus added by
  256.         //   InsertSystemSubMenu.
  257.         // o param is the item index of the chosen item
  258.         //   within theMenu
  259.         //
  260.         // Your implementation of this selector *may*
  261.         // call MenuSelect (directly or indirectly).
  262.         // Specifically, you can call ModalDialog while
  263.         // handling this selector.
  264.         // See "Notes on Recursion" (above) for more details.
  265. };
  266.  
  267. extern pascal OSStatus InsertSystemMenu(MenuRef theMenu,
  268.                                         SystemMenuCallbackProc callback, void *refcon);
  269.     // You can call this routine to add a menu to the system
  270.     // part of the menu bar.  [This is known as a "root" menu.]
  271.     // theMenu is a reference to the menu to add.  It must be a
  272.     // memory handle (as opposed to a resource handle) in the
  273.     // system heap.  Other utility routines in this module
  274.     // (GetNewSystemMenu and NewSystemMenu) create menus that
  275.     // way.  callback must be a pointer to your callback routine,
  276.     // as described above.  refcon is passed to your callback routine
  277.     // without interpretation.
  278.     //
  279.     // This routine must be called during startup time, ie before
  280.     // the Process Manager is launched.  Any attempt to call it after
  281.     // will not be effective (debug builds will DebugStr).
  282.     //
  283.     // The menu you add will not appear in the menu bar until
  284.     // the Process Manager is launched.  Moreover, the menu ID
  285.     // of the menu will not be decided until it is added to the
  286.     // menu bar.  Any time you need to operate on the menu,
  287.     // use the MenuRef.  If you must use the menu ID (because an
  288.     // API requires it), extract it from the MenuRef immediately
  289.     // before using it and don't cache it.
  290.     //
  291.     // Menus appear in the menu bar in the order in which you add
  292.     // them, with the first menu appearing on the left.  Also,
  293.     // if two distinct extensions that both use this module are
  294.     // installed, the first one's menus will appear to the left
  295.     // of the second's.
  296.  
  297. extern pascal OSStatus InsertSystemSubMenu(MenuRef rootMenu,
  298.                                         MenuRef parentMenu, UInt16 itemInParent, MenuRef childMenu);
  299.     // You can call this routine to add a hierarchical sub-menu
  300.     // to the menu bar.  You must call this routine in the context
  301.     // of a kSystemMenuPreSelectAdjust.  You must pass in rootMenu 
  302.     // the MenuRef of a system menu you registered using InsertSystemMenu.
  303.     // When an item on your sub-menu is chosen, the callback for
  304.     // the rootMenu will be called.  parentMenu is the menu in which
  305.     // the sub-menu is to appear.  This is typically rootMenu, unless
  306.     // you have sufficient bad taste to use multi-level
  307.     // hierarchical menus.  itemInParent is the item number where
  308.     // the sub-menu is to appear in the parent.  This must be between
  309.     // 1 and CountMenuItems(parentMenu), inclusive.  childMenu is the
  310.     // sub-menu itself.
  311.     //
  312.     // MoreSystemMenus will add childMenu to the menu bar with a
  313.     // temporary menu ID and set itemInParent of parentMenu to reference
  314.     // that temporary menu ID.  Before returning from its patch on MenuSelect,
  315.     // MoreSystemMenus will remove any these sub-menus from the menu
  316.     // bar (so that they don't conflict with application menus).
  317.     // Therefore, your callback must respond to kSystemMenuPreSelectAdjust 
  318.     // by inserting its sub-menus each time it is called.  Also, you must not
  319.     // rely on the menu ID of the sub-menu being constant, as the menu
  320.     // is dynamically renumbered each time it's added to the menu bar.
  321.  
  322. /////////////////////////////////////////////////////////////////
  323.  
  324. #pragma import reset // for clients
  325. #pragma export reset // for building a library
  326.  
  327. #ifdef __cplusplus
  328.     }
  329. #endif
  330.